﻿using Microsoft.Build.Framework;
using System.Text.Encodings.Web;
using System.Text.Json;

namespace NetByDocker.WarningLogger
{
    /// <summary>
    /// 警告信息输出
    /// 官网文档：https://learn.microsoft.com/zh-cn/visualstudio/msbuild/build-loggers?view=vs-2022
    /// 参考文档：https://mp.weixin.qq.com/s/vK6rH1A9pX06jwpEakxQUA
    /// </summary>
    /// <remarks>
    /// 1.构建该类库，然后生成该类库的dll文件
    /// 2.如果想针对某一个项目生成其警告文件，那么在他项目目录下执行该命令
    /// dotnet build -logger:"JsonErrorLogger,E:\xxx\my-example\src\NetByDocker.WarningLogger\bin\Debug\net8.0\NetByDocker.WarningLogger.dll"
    /// </remarks>
    public class JsonErrorLogger : Microsoft.Build.Framework.ILogger
    {
        private const string ErrorLogFileName = "json-error-logger.json";

        private static readonly JsonSerializerOptions JsonSerializerOptions = new()
                                                                              {
                                                                                  WriteIndented = true,
                                                                                  Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                                                                              };

        private readonly List<BuildError> _errors = new(), _warnings = new();

        public void Initialize(IEventSource eventSource)
        {
            eventSource.WarningRaised += EventSourceOnWarningRaised;
            eventSource.ErrorRaised += EventSourceOnErrorRaised;
        }

        private void EventSourceOnWarningRaised(object sender, BuildWarningEventArgs e)
        {
            _warnings.Add(new BuildError(e.Subcategory, e.Code, e.File, e.LineNumber, e.ColumnNumber,
                e.EndLineNumber,
                e.EndColumnNumber, e.Message, e.HelpKeyword, e.SenderName));
        }

        private void EventSourceOnErrorRaised(object sender, BuildErrorEventArgs e)
        {
            _errors.Add(new BuildError(e.Subcategory, e.Code, e.File, e.LineNumber, e.ColumnNumber,
                e.EndLineNumber,
                e.EndColumnNumber, e.Message, e.HelpKeyword, e.SenderName));
        }

        public void Shutdown()
        {
            using var fs = File.Create(ErrorLogFileName);
            JsonSerializer.Serialize(fs, new { warnings = _warnings, errors = _errors }, JsonSerializerOptions);

            _errors.Clear();
        }

        public LoggerVerbosity Verbosity { get; set; }

        public string? Parameters { get; set; }
    }

    public sealed record BuildError(
        string Subcategory,
        string Code,
        string File,
        int LineNumber,
        int ColumnNumber,
        int EndLineNumber,
        int EndColumnNumber,
        string? Message,
        string? HelpKeyword,
        string? SenderName);
}